/*
 * Ingenic mensa setup code
 *
 * Copyright (c) 2013 Ingenic Semiconductor Co.,Ltd
 * Author: Zoro <ykli@ingenic.cn>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <environment.h>
#include <netdev.h>
#include <regulator.h>
#include <asm/arch/jzsoc.h>
#include <asm/jz_mmc.h>
#include <u-boot/sha1.h>

extern int jz_net_initialize(bd_t *bis);

#ifdef CONFIG_BOARD_EARLY_INIT_F
int board_early_init_f(void)
{
	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;

//	regulator_init();
//	regulator_set_voltage(REGULATOR_CORE, CONFIG_SPL_CORE_VOLTAGE);

	/* switch SCLKA to EXCLK */
	writel((readl(cpm_regs + CPM_CPCCR) & 0x3fffffff) | (2 << 30), cpm_regs + CPM_CPCCR);
	while((readl(cpm_regs + CPM_CPCSR) & (1 << 0)));

	/* set CPU frequency to the target value */
	writel(CONFIG_SYS_APLL_MNOD | (1 << 8) | 0x20, cpm_regs + CPM_CPAPCR);
	while(!(readl(cpm_regs + CPM_CPAPCR) & (1 << 10)));

	/* switch SCLKA back to APLL */
	writel((readl(cpm_regs + CPM_CPCCR) & 0x3fffffff) | (1 << 30), cpm_regs + CPM_CPCCR);
	while((readl(cpm_regs + CPM_CPCSR) & (1 << 0)));

	/* disable pull for all pins */
	writel(0xffffffff, gpio_regs + GPIO_PXPEN(0));
	writel(0xffffffff, gpio_regs + GPIO_PXPEN(1));
	writel(0xffffffff, gpio_regs + GPIO_PXPEN(2));
	writel(0xffffffff, gpio_regs + GPIO_PXPEN(3));
	writel(0xffffffff, gpio_regs + GPIO_PXPEN(4));
	writel(0xffffffff, gpio_regs + GPIO_PXPEN(5));
	writel(0xffffffff, gpio_regs + GPIO_PXPEN(6));

	/* setup UART3 pins */
	writel(0x80000000, gpio_regs + GPIO_PXINTC(0));
	writel(0x80000000, gpio_regs + GPIO_PXMASKC(0));
	writel(0x80000000, gpio_regs + GPIO_PXPAT1C(0));
	writel(0x80000000, gpio_regs + GPIO_PXPAT0S(0));

	/* Power on TF-card */
	gpio_direction_output(GPIO_PB(3), 1);

	return 0;
}
#endif

#ifdef CONFIG_USB_GADGET
int jz_udc_probe(void);
void board_usb_init(void)
{
	printf("USB_udc_probe\n");
	jz_udc_probe();
}
#endif /* CONFIG_USB_GADGET */

int misc_init_r(void)
{
#if 0 /* TO DO */
	uint8_t mac[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc };

	/* set MAC address */
	eth_setenv_enetaddr("ethaddr", mac);
#endif

#if defined(CONFIG_CMD_BATTERYDET) && defined(CONFIG_BATTERY_INIT_GPIO)
	battery_init_gpio();
#endif
	return 0;
}

#ifdef CONFIG_MMC
int board_mmc_init(bd_t *bd)
{
	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
	uint32_t msc_cdr;

	/* setup MSC0 clock */
	msc_cdr = CONFIG_SYS_MPLL_FREQ / 50000000 / 2 - 1;
	writel(readl(cpm_regs + CPM_CLKGR) & ~CPM_CLKGR_MSC0, cpm_regs + CPM_CLKGR);
	writel(msc_cdr | CPM_MSCCDR_MPCS_MPLL | CPM_MSCCDR_CE, cpm_regs + CPM_MSC0CDR);
	while (readl(cpm_regs + CPM_MSC0CDR) & CPM_MSCCDR_MSC_BUSY);

	/* setup MSC0 pins */
	writel(0x00fc00f0, gpio_regs + GPIO_PXINTC(0));
	writel(0x00fc00f0, gpio_regs + GPIO_PXMASKC(0));
	writel(0x00fc00f0, gpio_regs + GPIO_PXPAT1C(0));
	writel(0x00fc00f0, gpio_regs + GPIO_PXPAT0S(0));

	jz_mmc_init((void __iomem *)MSC0_BASE);

	return 0;
}
#endif

int board_eth_init(bd_t *bis)
{
	int rv;
#ifndef  CONFIG_USB_ETHER
	/*  initialize jz4775 gpio */
//	gpio_set_func(GPIO_PORT_B, GPIO_FUNC_1, 0x0003fc10);
//	gpio_set_func(GPIO_PORT_D, GPIO_FUNC_1, 0x3c000000);
//	gpio_set_func(GPIO_PORT_F, GPIO_FUNC_0, 0x0000fff0);
//	udelay(100000);

	/*  reset DM9161 */
//	gpio_direction_output(CONFIG_GPIO_DM9161_RESET, CONFIG_GPIO_DM9161_RESET_ENLEVEL);
//	mdelay(10);
//	gpio_set_value(CONFIG_GPIO_DM9161_RESET, !CONFIG_GPIO_DM9161_RESET_ENLEVEL);
//	mdelay(10);

	rv = jz_net_initialize(bis);
#else
	rv = usb_eth_initialize(bis);
#endif

	return rv;
}

#ifdef CONFIG_DISPLAY_BOARDINFO
/* U-Boot common routines */
int checkboard(void)
{
	puts("Board: CU4775-Neo (Ingenic XBurst JZ4775 SoC)\n");

	return 0;
}
#endif

#ifdef CONFIG_SPL_BUILD
void spl_board_init(void)
{
}
#endif /* CONFIG_SPL_BUILD */
